基于STM32的ModBus实现(二)移植FreeMODBUS TCP

您所在的位置:网站首页 modbus tcp 客户端 服务器 基于STM32的ModBus实现(二)移植FreeMODBUS TCP

基于STM32的ModBus实现(二)移植FreeMODBUS TCP

2024-07-17 04:22| 来源: 网络整理| 查看: 265

一、ModBusTCP

  Modbus TCP是一种基于TCP/IP协议的Modbus通信协议的变种。它允许Modbus协议在以太网上进行通信,提供了一种简单而有效的方式来连接不同类型的设备,如传感器、执行器、PLC等。Modbus TCP使用标准的TCP/IP协议栈,因此可以在现有的以太网基础设施上运行,而无需额外的硬件支持。这使得它在工业自动化和物联网应用中非常流行。 Modbus TCP使用客户端-服务器模型,其中客户端发送请求并接收响应,而服务器则响应请求并提供所需的数据。

二、STM32移植ModBusTCP

  移植文件参考上一节的ModBusRTU移植,需要将ModBusRTU的接口文件修改为支持TCP。

硬件:STM32F407ZGT6、DP83848 PHY 软件:FreeRTOS、LwIP2.1.2、FreeModbus、STM32F4标准库

以下为移植的具体流程:

2.1、STM32 + DP83848 实现MAC

  第一步当然打通硬件的连接,通过以太网ETH外设驱动DP83848实现以太网MAC数据链路层的通信。

  具体流程可以参考基于STM32F407MAC与DP83848实现以太网通讯三(STM32F407MAC配置以及数据收发)

2.2、STM32移植LwIP协议栈

  在完成了数据链路层的通信后,在STM32上要实现UDP/TCP协议需要移植LwIP协议栈,我这里使用的为LwIP2.1.2,移植可以参考基于STM32F407MAC与DP83848实现以太网通讯五(裸机移植LwIP协议栈)。

  如果是对LwIP协议栈不熟悉的话就需要通过网上的资料学习了:LwIP应用开发实战指南

2.3、将FreeRTOS移植到STM32并支持LwIP

  在完成了STM32的ETH驱动以及移植LwIP协议栈后,还需要移植FreeRTOS,以及在移植FreeRTOS后修改LwIP的相关配置以支持LwIP的NETCONN和SKCOT编程。

2.4、移植FreeModBusTCP

  上述的移植工作还是比较花时间的,可以在网上找一下模板,或者支持自己开发板的相关例程,只要能够正常连接电脑Ping通就可以。

  在完成了上述工作后就可以移植ModBusTCP了,我是在我自己移植好的LwIP和FreeRTOS的程序上先实现ModBusRTU,确保ModBus除了接口这一块都没问题,参考上一节:基于STM32的ModBus实现(一)移植FreeMODBUS RTU。

2.4.1、FreeModBusTCP的Port文件

  在FreeMODBUSV1.6文件中我们找到Demo/MCF5235TCP/port,这个里面存放了MCF5235的LwIP的FreeModBusTCP接口文件,尽管使用到的硬件不一样但是LwIP的TCP层是不基于硬件的,所以可以直接拿过来修改并使用,以下是port文件夹中的文件,我们直接添加到工程,如果是基于之前的ModBusRTU的程序的话,就需要把RTU相关的接口文件从工程删除。

  还需要调整使用的ModBus源文件文件,ModBus ASCII/RTU相关的.c文件就不需要了,将mbtcp.c添加到工程中,还有porttcp.c对应的接口文件port.h文件的路径添加到工程。

01-FreeModBusfile.png

06-inlcude.png

porttcp.c: ModBusTCP接口文件 portother.c: 实现了打印日志的功能 portevent.c: LwIP邮箱机制的操作 2.4.2 porttcp.c

  porttcp.c中的TCP 是由RAW的方式实现的

xMBTCPPortInit(): 创建TCP控制块、绑定IP以及注册回调函数 prvvMBPortReleaseClient(): 关闭TCP链接由vMBTCPPortClose调用 vMBTCPPortClose(): 关闭TCP链接 prvxMBTCPPortAccept(): TCP接收回调函数 prvxMBTCPPortReceive(): 底层接收数据由prvxMBTCPPortAccept调用 xMBTCPPortSendResponse(): ModTCP发送数据

porttcp.c代码如下

portserial.c /* * FreeModbus Libary: lwIP Port * Copyright (C) 2006 Christian Walter * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * * File: $Id$ */ /* ----------------------- System includes ----------------------------------*/ #include #include #include "port.h" /* ----------------------- lwIP includes ------------------------------------*/ #include "lwip/api.h" #include "lwip/tcp.h" /* ----------------------- Modbus includes ----------------------------------*/ #include "mb.h" #include "mbport.h" /* ----------------------- MBAP Header --------------------------------------*/ #define MB_TCP_UID 6 #define MB_TCP_LEN 4 #define MB_TCP_FUNC 7 /* ----------------------- Defines -----------------------------------------*/ #define MB_TCP_DEFAULT_PORT 502 /* TCP listening port. */ #define MB_TCP_BUF_SIZE ( 256 + 7 ) /* Must hold a complete Modbus TCP frame. */ /* ----------------------- Prototypes ---------------------------------------*/ void vMBPortEventClose( void ); void vMBPortLog( eMBPortLogLevel eLevel, const CHAR * szModule, const CHAR * szFmt, ... ); /* ----------------------- Static variables ---------------------------------*/ static struct tcp_pcb *pxPCBListen; static struct tcp_pcb *pxPCBClient; static UCHAR aucTCPBuf[MB_TCP_BUF_SIZE]; static USHORT usTCPBufPos; /* ----------------------- Static functions ---------------------------------*/ static err_t prvxMBTCPPortAccept( void *pvArg, struct tcp_pcb *pxPCB, err_t xErr ); static err_t prvxMBTCPPortReceive( void *pvArg, struct tcp_pcb *pxPCB, struct pbuf *p, err_t xErr ); static void prvvMBTCPPortError( void *pvArg, err_t xErr ); /* ----------------------- Begin implementation -----------------------------*/ BOOL xMBTCPPortInit( USHORT usTCPPort ) { struct tcp_pcb *pxPCBListenNew, *pxPCBListenOld; BOOL bOkay = FALSE; USHORT usPort; if( usTCPPort == 0 ) { usPort = MB_TCP_DEFAULT_PORT; } else { usPort = ( USHORT ) usTCPPort; } if( ( pxPCBListenNew = pxPCBListenOld = tcp_new( ) ) == NULL ) { /* Can't create TCP socket. */ bOkay = FALSE; } else if( tcp_bind( pxPCBListenNew, IP_ADDR_ANY, ( u16_t ) usPort ) != ERR_OK ) { /* Bind failed - Maybe illegal port value or in use. */ ( void )tcp_close( pxPCBListenOld ); bOkay = FALSE; } else if( ( pxPCBListenNew = tcp_listen( pxPCBListenNew ) ) == NULL ) { ( void )tcp_close( pxPCBListenOld ); bOkay = FALSE; } else { /* Register callback function for new clients. */ tcp_accept( pxPCBListenNew, prvxMBTCPPortAccept ); /* Everything okay. Set global variable. */ pxPCBListen = pxPCBListenNew; #ifdef MB_TCP_DEBUG vMBPortLog( MB_LOG_DEBUG, "MBTCP-ACCEPT", "Protocol stack ready.\r\n" ); #endif } bOkay = TRUE; return bOkay; } void prvvMBPortReleaseClient( struct tcp_pcb *pxPCB ) { if( pxPCB != NULL ) { if( tcp_close( pxPCB ) != ERR_OK ) { tcp_abort( pxPCB ); } if( pxPCB == pxPCBClient ) { #ifdef MB_TCP_DEBUG vMBPortLog( MB_LOG_DEBUG, "MBTCP-CLOSE", "Closed connection to %d.%d.%d.%d.\r\n", ip4_addr1( &( pxPCB->remote_ip ) ), ip4_addr2( &( pxPCB->remote_ip ) ), ip4_addr3( &( pxPCB->remote_ip ) ), ip4_addr4( &( pxPCB->remote_ip ) ) ); #endif pxPCBClient = NULL; } if( pxPCB == pxPCBListen ) { pxPCBListen = NULL; } } } void vMBTCPPortClose( ) { /* Shutdown any open client sockets. */ prvvMBPortReleaseClient( pxPCBClient ); /* Shutdown or listening socket. */ prvvMBPortReleaseClient( pxPCBListen ); /* Release resources for the event queue. */ vMBPortEventClose( ); } void vMBTCPPortDisable( void ) { prvvMBPortReleaseClient( pxPCBClient ); } err_t prvxMBTCPPortAccept( void *pvArg, struct tcp_pcb *pxPCB, err_t xErr ) { err_t error; if( xErr != ERR_OK ) { return xErr; } /* We can handle only one client. */ if( pxPCBClient == NULL ) { /* Register the client. */ pxPCBClient = pxPCB; /* Set up the receive function prvxMBTCPPortReceive( ) to be called when data * arrives. */ tcp_recv( pxPCB, prvxMBTCPPortReceive ); /* Register error handler. */ tcp_err( pxPCB, prvvMBTCPPortError ); /* Set callback argument later used in the error handler. */ tcp_arg( pxPCB, pxPCB ); /* Reset the buffers and state variables. */ usTCPBufPos = 0; #ifdef MB_TCP_DEBUG vMBPortLog( MB_LOG_DEBUG, "MBTCP-ACCEPT", "Accepted new client %d.%d.%d.%d\r\n", ip4_addr1( &( pxPCB->remote_ip ) ), ip4_addr2( &( pxPCB->remote_ip ) ), ip4_addr3( &( pxPCB->remote_ip ) ), ip4_addr4( &( pxPCB->remote_ip ) ) ); #endif error = ERR_OK; } else { prvvMBPortReleaseClient( pxPCB ); error = ERR_OK; } return error; } /* Called in case of an unrecoverable error. In any case we drop the client * connection. */ void prvvMBTCPPortError( void *pvArg, err_t xErr ) { struct tcp_pcb *pxPCB = pvArg; if( pxPCB != NULL ) { #ifdef MB_TCP_DEBUG vMBPortLog( MB_LOG_DEBUG, "MBTCP-ERROR", "Error with client connection! Droping it.\r\n" ); #endif prvvMBPortReleaseClient( pxPCB ); } } err_t prvxMBTCPPortReceive( void *pvArg, struct tcp_pcb *pxPCB, struct pbuf *p, err_t xErr ) { USHORT usLength; err_t error; if( xErr != ERR_OK ) { return xErr; } /* If pbuf is NULL then remote end has closed connection. */ if( p == NULL ) { prvvMBPortReleaseClient( pxPCB ); return ERR_OK; } /* Acknowledge that we have received the data bytes. */ tcp_recved( pxPCB, p->len ); /* Check for internal buffer overflow. In case of an error drop the * client. */ if( ( usTCPBufPos + p->len ) >= MB_TCP_BUF_SIZE ) { prvvMBPortReleaseClient( pxPCB ); error = ERR_OK; } else { memcpy( &aucTCPBuf[usTCPBufPos], p->payload, p->len ); usTCPBufPos += p->len; /* If we have received the MBAP header we can analyze it and calculate * the number of bytes left to complete the current request. If complete * notify the protocol stack. */ if( usTCPBufPos >= MB_TCP_FUNC ) { /* Length is a byte count of Modbus PDU (function code + data) and the * unit identifier. */ usLength = aucTCPBuf[MB_TCP_LEN]


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3